import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import pandas as pd
import threading
from itertools import cycle

class ExamSchedulerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("考试安排工具")
        self.root.geometry("800x600")

        self.data_frames = {}
        self.result_data_frames = {}  # 初始化结果数据字典
        self.scheduled_students = set()  # 存储已排考的学生姓名
        self.lock = threading.Lock()  # 添加锁来管理线程安全

        # 创建一个 Frame 容器来放置按钮
        button_frame = tk.Frame()
        button_frame.pack()

        # 按钮
        self.open_button = tk.Button(button_frame, text="打开", command=self.open_file)
        self.open_button.pack(side=tk.LEFT, padx=5, pady=10)

        self.schedule_button = tk.Button(button_frame, text="排考场", command=self.schedule_exam)
        self.schedule_button.pack(side=tk.LEFT, padx=5, pady=10)

        self.export_button = tk.Button(button_frame, text="导出", command=self.export_file)
        self.export_button.pack(side=tk.LEFT, padx=5, pady=10)

        # Notebook组件
        self.notebook = ttk.Notebook(root)
        self.notebook.pack(expand=True, fill='both')

    def open_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
        if not file_path:
            return

        # 读取电子表格
        xls = pd.ExcelFile(file_path)
        self.data_frames = {
            sheet_name: xls.parse(sheet_name)[['年级', '班级', '姓名']].apply(
                lambda col: col.map(lambda x: x.strip() if isinstance(x, str) else x))
            for sheet_name in xls.sheet_names
        }

        # 清空Notebook
        for tab in self.notebook.tabs():
            self.notebook.forget(tab)

        # 为每个年级创建一个选项卡
        for sheet_name, df in self.data_frames.items():
            frame = ttk.Frame(self.notebook)
            self.notebook.add(frame, text=sheet_name)

            # 创建Treeview和垂直滚动条
            tree = ttk.Treeview(frame, columns=("年级","班级", "姓名", "座号",'考点'), show='headings')
            v_scrollbar = ttk.Scrollbar(frame, orient="vertical", command=tree.yview)
            tree.configure(yscrollcommand=v_scrollbar.set)

            # 设置列宽
            for col in ["年级","班级", "姓名", "座号",'考点']:
                tree.heading(col, text=col)
                tree.column(col, width=18)  # 设置列宽为18

            tree.pack(side='left', expand=True, fill='both')
            v_scrollbar.pack(side='right', fill='y')

            for _, row in df.iterrows():
                tree.insert("", "end", values=row.tolist() + [''] * 4)  # 预留所有列信息

        messagebox.showinfo("信息", "文件加载完成")

    def schedule_exam(self):
        threading.Thread(target=self.schedule_in_background).start()  # 启动新线程进行排考

    def schedule_in_background(self):
        print("开始排考")
        for sheet_name, df in self.data_frames.items():
            print(f"处理表: {sheet_name}")  # 添加调试打印
            results = []
            df_grouped = df[['班级', '姓名']]
            class_data = df_grouped.groupby('班级')['姓名'].apply(list).to_dict()

            scheduled_students_local = set()  # 当前年级已排考学生
            all_classes = list(class_data.keys())  # 所有班级列表

            for class_name, students in class_data.items():
                print(f"  当前班级: {class_name}, 学生数: {len(students)}")  # Debug print
                if not students:
                    continue

                # 过滤掉已排考的学生
                other_classes = [cn for cn in class_data.keys() if cn != class_name]
                other_students = {oc: [name for name in class_data[oc] if (name,oc) not in scheduled_students_local] for oc in
                                  other_classes}

                scheduled = []
                num_students = len(students)

                # 创建一个从当前班级的下一个班级开始的循环迭代器
                start_index = (all_classes.index(class_name) + 1) % len(all_classes)
                other_classes_cycle = cycle(all_classes[start_index:] + all_classes[:start_index])

                for _ in range(num_students):
                    # 从循环中选择其他班级
                    for oc in other_classes_cycle:
                        if oc in other_students and other_students[oc]:  # 确保班级存在且有可用学生
                            other_student = other_students[oc].pop(0)  # 从其他班级中选一个学生
                            scheduled.append((other_student, oc))
                            # print(f"已排考学生：{other_student} 来自班级 {oc}")  # Debug print
                            break  # 选择完一个学生后，跳出循环以选择下一个学生

                # 添加结果
                for idx, (name, original_class) in enumerate(scheduled):
                    if idx < num_students:  # 确保不超出学生数量
                        results.append(
                            [sheet_name, original_class, name, idx + 1, str(sheet_name) + str(class_name)]
                        )
                        self.scheduled_students.add((name, original_class))  # 添加已排考学生到集合中
                        print(f"已排考学生：{name} 来自班级 {original_class}")
                        scheduled_students_local.add((name,original_class))

            # 更新结果DataFrame
            result_df = pd.DataFrame(results, columns=["年级", "班级", "姓名", "座号", '考点'])

            # 将结果DataFrame添加到result_data_frames
            self.result_data_frames[sheet_name] = result_df

            # 更新树形控件
            self.update_tree_view(sheet_name, result_df)

        messagebox.showinfo("信息", "排考场完成")

    def update_tree_view(self, sheet_name, result_df):
        # 查找对应的选项卡
        for tab in self.notebook.tabs():
            if self.notebook.tab(tab, "text") == sheet_name:
                frame = self.notebook.nametowidget(tab)
                tree = frame.winfo_children()[0]  # 获取Treeview控件
                tree.delete(*tree.get_children())  # 清空现有数据

                for _, row in result_df.iterrows():
                    tree.insert("", "end", values=row.tolist())  # 插入新的数据

    def export_file(self):
        file_path = filedialog.asksaveasfilename(defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx")])
        if not file_path:
            return

        # 创建一个ExcelWriter对象
        with pd.ExcelWriter(file_path) as writer:
            # 导出原始数据
            for sheet_name, df in self.data_frames.items():
                df.to_excel(writer, sheet_name=f"原始_{sheet_name}", index=False)

            # 导出排考生成的数据
            for sheet_name, result_df in self.result_data_frames.items():
                result_df.to_excel(writer, sheet_name=f"排考_{sheet_name}", index=False)

        messagebox.showinfo("信息", "导出完成")


if __name__ == "__main__":
    root = tk.Tk()
    app = ExamSchedulerApp(root)
    root.mainloop()
